/*
 * Copyright (c) 2022-2023, Arm Limited and Contributors. All rights reserved.
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef IOTSDK_NTP_CLIENT_H
#define IOTSDK_NTP_CLIENT_H

#include "cmsis_os2.h"
#include "fff.h"

#include <stdint.h>
#include <time.h>

#ifdef __cplusplus
extern "C" {
#endif

#define NTP_DEFAULT_NIST_SERVER_HOSTNAME "pool.ntp.org"
#define NTP_DEFAULT_NIST_SERVER_PORT     123
#define NTP_DEFAULT_INTERVAL_MS          15000 // 15s

/** Callback called when NTP time is updated successfully. */
typedef void (*iotNtpCb_t)(time_t time, void *ctx);

typedef enum {
    IOT_NTP_CLIENT_UNINITIALISED = 0,
    IOT_NTP_CLIENT_STOPPED,
    IOT_NTP_CLIENT_RUNNING,
} iotNtpClientState_t;

typedef enum {
    IOT_NTP_CLIENT_OK = 0,          /**< No error. */
    IOT_NTP_CLIENT_ERR_WRONG_STATE, /**< Wrong NTP state. */
    IOT_NTP_CLIENT_ERR_INVALID_ARG, /**< Error due to invalid arguments. */
    IOT_NTP_CLIENT_ERR_THREAD,      /**< Error thread. */
    IOT_NTP_CLIENT_ERR_MUTEX,       /**< Error thread. */
    IOT_NTP_CLIENT_ERR_EVENT_QUEUE, /**< Error event queue. */
    IOT_NTP_CLIENT_ERR_EVENT_FLAG,  /**< Error event flag. */
    IOT_NTP_CLIENT_ERR_NETWORK,     /**< Error network. */
    IOT_NTP_CLIENT_ERR_TIMER,       /**< Error timer. */
    IOT_NTP_CLIENT_ERR_INTERNAL     /**< Internal error (e.g mutex initalizaiton failed) */
} iotNtpClientResult_t;

typedef struct {
    /** Time server hostname */
    char *hostname;
    /** Time server port */
    uint32_t port;
    /** Update interval. The time is updated immediately when the client starts and again every time this interval
     * elapses.
     */
    uint32_t interval_ms;
} iotNtpClientConfig_t;

typedef struct iotNtpClientListener_s {
    /** NTP callback function */
    iotNtpCb_t cb;
    /** Listener context */
    void *ctx;
    /** Next listener on the list */
    struct iotNtpClientListener_s *next;
} iotNtpClientListener_t;

typedef struct {
    /** NTP client configuration */
    iotNtpClientConfig_t config;
    /** NTP client listeners list */
    iotNtpClientListener_t listeners;
    /** NTP client current state */
    iotNtpClientState_t state;
    /** NTP client error code */
    iotNtpClientResult_t error;
    /** NTP client thread */
    osThreadId_t thread;
    /** NTP client mutex */
    osMutexId_t mutex;
    /** NTP client event queue */
    osMessageQueueId_t event_queue;
    /** NTP client event flags */
    osEventFlagsId_t event_flags;
    /** NTP client current time */
    time_t time;
} iotNtpClientContext_t;

DECLARE_FAKE_VALUE_FUNC(time_t, iotNtpClientGetTime);
DECLARE_FAKE_VALUE_FUNC(iotNtpClientState_t, iotNtpClientGetState);
DECLARE_FAKE_VALUE_FUNC(iotNtpClientResult_t, iotNtpClientDeinit);
DECLARE_FAKE_VALUE_FUNC(iotNtpClientResult_t, iotNtpClientStop);
DECLARE_FAKE_VALUE_FUNC(iotNtpClientResult_t, iotNtpClientStart);
DECLARE_FAKE_VALUE_FUNC(iotNtpClientResult_t, iotNtpClientAddListener, iotNtpCb_t, void *);
DECLARE_FAKE_VALUE_FUNC(iotNtpClientResult_t, iotNtpClientInit, const iotNtpClientConfig_t *);
DECLARE_FAKE_VALUE_FUNC(iotNtpClientResult_t, iotNtpClientClearListeners);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // IOTSDK_NTP_CLIENT_H
